#include "../Header/Precompiled.h"
#include "../Header/WindowsSystem.h"
#include "../Header/GameStateMgr.h"
WindowsSystem* pWinSystem = NULL; // pointer to Windows system for use in Windows message handling procedure

//Used by windows to identify our window class type
//(needed for registering/creating/unregistering the window)
const char windowsClassName[] = "EngineWindowClass";

//The message handling procedure for the game
LRESULT WINAPI MessageHandler(HWND hWnd,	 //The window the message is for (ours in this case)
	UINT msg,		 //The message type
	WPARAM wParam, //The primary data for the message
	LPARAM lParam) //The secondary data for the message (if any)
{
	//See what type of message it is
	switch(msg)
	{
	case WM_CHAR: //A character key was pressed
		{
			// check if user requested restart
			switch(wParam)
			{
			case 'r':
				gGameStateNext = 1;
				break;
			default:
				// Create a key message, set the character pressed (the wParam 
				// is the ascii value), then broadcast the message to all systems.
				Shout(&KeyDownMessage(wParam,MT_CharDown));
				break;
			}
			break;
		}
	/*case WM_LBUTTONDOWN:
		{
			MouseButton m(MouseButton::LeftMouse,true,Vec2(WINDOWSSYSTEM->MousePosition.x,WINDOWSSYSTEM->MousePosition.y));
			Shout(&m);
			break;
		}
	case WM_RBUTTONDOWN:
		{
			MouseButton m(MouseButton::RightMouse,true,Vec2(WINDOWSSYSTEM->MousePosition.x,WINDOWSSYSTEM->MousePosition.y));
			Shout(&m);
			break;
		}
	case WM_LBUTTONUP:
		{
			MouseButton m(MouseButton::LeftMouse,false,Vec2(WINDOWSSYSTEM->MousePosition.x,WINDOWSSYSTEM->MousePosition.y));
			Shout(&m);
			break;
		}
	case WM_RBUTTONUP:
		{
			MouseButton m(MouseButton::RightMouse,false,Vec2(pWinSystem->MousePos.x,pWinSystem->MousePos.y));
			Shout(&m);
			break;
		}
	case WM_MOUSEMOVE:
		{
			pWinSystem->MousePos = MAKEPOINTS( lParam );
			MouseMove m(Vector2D(pWinSystem->MousePos.x, pWinSystem->MousePos.y));
			Shout(&m);
			break;
		}*/
	case WM_KEYDOWN: //A key was pressed
		// Create a key down message with the wParam
		// and broadcast the message to all systems.
		switch(wParam)
		{
		case VK_ESCAPE:
			gGameStateNext = 0;
			break;
		default:
			Shout(&KeyDownMessage(wParam));
			break;
		}
		break;
	case WM_KEYUP: //A key was released
		//TODO: Handle any key logic you might need for game controls
		break;
	case WM_DESTROY: //A destroy message--time to kill the game
		//Make sure we shut everything down properly by telling Windows
		//to post a WM_QUIT message (the parameter is the exit code).
		PostQuitMessage(0);
		return 0;
	case WM_SYSKEYDOWN:
		{
			//Eat the WM_SYSKEYDOWN message to prevent freezing the game when
			//the alt key is pressed
			switch( wParam )
			{
			case VK_LMENU:
			case VK_RMENU:
				return 0; //Stop Alt key from stopping the winProc
			case VK_F4:
				//Check for Alt F4
				DWORD dwAltKeyMask = ( 1 << 29 );
				if( ( lParam & dwAltKeyMask ) != 0 )
					PostQuitMessage(0);
				return 0;
			}
			return 0;
		}
	}

	//We didn't completely handle the message, so pass it on for Windows to handle.
	return DefWindowProc(hWnd, msg, wParam, lParam);
}

WindowsSystem::WindowsSystem(const char* windowTitle, int ClientWidth, int ClientHeight)
{
	//Set the pointer to the windows system (used by message proc for reading mouse data)

	// The size passed to CreateWindow is the full size including the windows border and caption 
	// AdjustWindowRect will adjust the provided rect so that the client size of the window is the desired size
	RECT fullWinRect = {0, 0, ClientWidth, ClientHeight};
	AdjustWindowRect(&fullWinRect,	// rect for the full size of the window
		WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU,// style of the window, which must match what is passed in to CreateWindow below
		FALSE);									// Does this window have a menu?

	//Register the window class for the game.
	WNDCLASSEX wc = {sizeof(WNDCLASSEX),	// size of this structure (passing the size allows Microsoft to update their interfaces and maintain backward compatibility)
		CS_CLASSDC,							// style of the window class--this is the base type (one device context for all windows in the process)
		MessageHandler,					// name of the message handling function
		0L, 0L,									// amount of extra memory to allocate for this class and window
		GetModuleHandle(NULL),				// handle to the instance that has the windows procedure--NULL means use this file.
		NULL,													// add an Icon as a resource and add them here
		LoadCursor(NULL, IDC_ARROW),	// use the default arrow cursor
		NULL, NULL,										// background brush and menu--these can be NULL
		windowsClassName, NULL};			// class name and the small icon (NULL just uses the default)

	RegisterClassEx(&wc);

	// Store the handle to the instance.
	hInstance = wc.hInstance;

	// Create the game's window.
	hWnd = CreateWindow(windowsClassName,	// class name
		windowTitle,								// name for the title bar
		WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU,// style of the window (WS_BORDER, WS_MINIMIZEBOX, WS_MAXIMIZE, etc.)
		CW_USEDEFAULT, CW_USEDEFAULT,				// x and y pos of the window (screen coords for base windows, relative coords for child windows)
		fullWinRect.right-fullWinRect.left,	// width of the window, including borders
		fullWinRect.bottom-fullWinRect.top,	// height of the window, including borders and caption
		GetDesktopWindow(),					// parent window
		NULL,												// menu for the window
		hInstance,									// handle to the instance of the window (ignored in NT/2K/XP)
		NULL);											// lParam for the WM_CREATE message of this window
}

void WindowsSystem::ActivateWindow()
{
	//Show the window (could also be SW_SHOWMINIMIZED, SW_SHOWMAXIMIZED, etc.)
	ShowWindow(hWnd, SW_SHOWDEFAULT);
	//Send a WM_PAINT message to the window
	UpdateWindow(hWnd);
}

//Process any windows messages and run the game until we get a quit message
//While we don't use the window handle, in other cases we might want to only process messages for this window
void WindowsSystem::Update(float dt)
{
	MSG msg;
	// Look for any pending windows messages, remove them, then handle them.
	// It is important to get all windows messages available not just one -- don't want to miss anything critical.
	while (PeekMessage(&msg, // address of variable to store message in
		NULL,		// window handle--NULL just means get any message from the current thread
		0U,			// start message type to process
		0U,			// end message type to process
		PM_REMOVE)) // determines whether or not the message is removed
	{
		TranslateMessage(&msg);	//Makes sure WM_CHAR and similar messages are generated
		DispatchMessage(&msg);	//Calls the message procedure (see below) with this message

		//If we get a quit message, set the game state to quit
		if (msg.message == WM_QUIT)
			break; // it wouldn't compile so I added this.
	}
}

WindowsSystem::~WindowsSystem()
{
	//Unregister the window class
	UnregisterClass(windowsClassName, hInstance);
}
